# Return a flat list of libs including target linking requirements.
function(gdal_flatten_link_libraries _result)
    set(_libs "")
    while(ARGN)
        list(GET ARGN 0 _lib)
        list(REMOVE_AT ARGN 0)
        gdal_resolve_link_genex(_lib "${_lib}")
        if(_lib)
            list(APPEND _libs "${_lib}")
            if(TARGET "${_lib}")
                get_target_property(_link_libraries ${_lib} INTERFACE_LINK_LIBRARIES)
                get_target_property(_type ${_lib} TYPE)
                if(_link_libraries AND NOT TYPE STREQUAL "SHARED_LIBRARY")
                    list(INSERT ARGN 0 ${_link_libraries})
                endif()
            endif()
        endif()
    endwhile()
    set(${_result} "${_libs}" PARENT_SCOPE)
endfunction()

# Resolve all generator expressions for the purpose of exporting linker flags.
function(gdal_resolve_link_genex _result _input)
    while(_input MATCHES "^(.*)(\\\$<[^>]*>)")
        set(_match "${CMAKE_MATCH_0}")
        set(_first "${CMAKE_MATCH_1}")
        gdal_evaluate_link_genex(_second "${CMAKE_MATCH_2}")
        string(REPLACE "${_match}" "${_first}${_second}" _input "${_input}")
    endwhile()
    set("${_result}" "${_input}" PARENT_SCOPE)
endfunction()

# Resolve a single generator expressions for the purpose of exporting linker flags.
function(gdal_evaluate_link_genex _result _genex)
    if(_genex MATCHES "^\\\$<(LINK_ONLY|1):(.*)>\$")
        set(_genex "${CMAKE_MATCH_2}")
    elseif(_genex MATCHES "^\\\$<([^:]*COMPILER_ID):([^>]*)>\$")
        string(REPLACE "," ";" compiler_ids "${CMAKE_MATCH_2}")
        if("${CMAKE_${CMAKE_MATCH_1}}" IN_LIST compiler_ids)
            set(_genex 1)
        else()
            set(_genex 0)
        endif()
    elseif(_genex MATCHES "^\\\$<0:(.*)>\$")
        set(_genex "")
    else()
        message(WARNING "Dropping unsupported generator expression: '${_genex}'")
        set(_genex "")
    endif()
    set(${_result} "${_genex}" PARENT_SCOPE)
endfunction()


# Get a target property with respect to the current build type
function(gdal_get_target_property_for_config _result _target _property)
    string(TOUPPER "${CMAKE_BUILD_TYPE}" config)
    get_target_property(_config_list ${_target} MAP_IMPORTED_CONFIG_${config})
    if (NOT _config_list)
        get_target_property(_config_list ${_target} IMPORTED_CONFIGURATIONS)
    endif ()
    set(value "")
    foreach (config IN LISTS _config_list)
        string(TOUPPER "${config}" config)
        get_target_property(value ${_target} ${_property}_${config})
        if(value)
            break()
        endif()
    endforeach ()
    if(NOT value)
        get_target_property(value ${_target} ${_property})
    endif()
    set(${_result} "${value}" PARENT_SCOPE)
endfunction()

# Guess linker parameters (-L/osgeo -lproj) from file name (/osgeo/libproj.dll.a).
function(gdal_split_library_to_lflags _lib_flag _path_flag _input)
    get_filename_component(_lib_name "${_input}" NAME)
    foreach(_item IN ITEMS SHARED IMPORT STATIC)
        set(_suffix "${CMAKE_${_item}_LIBRARY_SUFFIX}")
        if(NOT _suffix)
            continue()
        endif()
        string(FIND "${_lib_name}" "${_suffix}" _pos REVERSE)
        if(_pos EQUAL "-1")
            continue()
        endif()
        string(SUBSTRING "${_lib_name}" 0 "${_pos}" _name_we)
        if(NOT "${_name_we}${_suffix}" STREQUAL _lib_name)
            continue()
        endif()
        set(_prefix "${CMAKE_${_item}_LIBRARY_PREFIX}")
        if(_prefix)
            string(FIND "${_name_we}" "${_prefix}" _pos)
        else()
            set(_pos 0)
        endif()
        if(_pos STREQUAL "0")
            # Match
            string(LENGTH "${_prefix}" _pos)
            string(SUBSTRING "${_name_we}" "${_pos}" "-1" _lib_name)
            set(${_lib_flag} "${CMAKE_LINK_LIBRARY_FLAG}${_lib_name}" PARENT_SCOPE)
            get_filename_component(_lib_dir "${_input}" DIRECTORY)
            if(_lib_dir AND NOT _lib_dir IN_LIST CMAKE_C_IMPLICIT_LINK_DIRECTORIES)
                set(${_path_flag} "${CMAKE_LIBRARY_PATH_FLAG}${_lib_dir}" PARENT_SCOPE)
            else()
                set(${_path_flag} "" PARENT_SCOPE)
            endif()
            return()
        endif()
    endforeach()
    # Fallback
    set(${_lib_flag} "${_input}")
    set(${_path_flag} "" PARENT_SCOPE)
endfunction()

# Get linker flags for cmake link libraries, with targets and generator
# expressions resolved for the current build type.
function(gdal_get_lflags _result)
    gdal_flatten_link_libraries(_libs_in ${ARGN})
    set(_libs_out "")
    while(_libs_in)
        list(GET _libs_in 0 _lib)
        list(REMOVE_AT _libs_in 0)
        if(TARGET "${_lib}")
            get_property(_type TARGET ${_lib} PROPERTY TYPE)
            if(_type STREQUAL "INTERFACE_LIBRARY")
                continue()
            endif()
            gdal_get_target_property_for_config(_location "${_lib}" "IMPORTED_LOCATION")
            if(_location)
                set(_lib "${_location}")
            endif()
        endif()
        set(_other "")
        if(CMAKE_LIBRARY_PATH_FLAG STREQUAL "-L" AND _lib MATCHES "^-L")
            set(_other "${_lib}")
            set(_lib "")
        elseif(_lib STREQUAL "-pthread")
            # use _lib
        elseif(CMAKE_LINK_LIBRARY_FLAG STREQUAL "-l" AND _lib MATCHES "^-l")
            # use _lib
        elseif(EXISTS "${_lib}")
            gdal_split_library_to_lflags(_lib _other "${_lib}")
        else()
            set(_lib "${CMAKE_LINK_LIBRARY_FLAG}${_lib}")
        endif()
        if(_other AND NOT _other IN_LIST _libs_out)
            list(APPEND _libs_out "${_other}")
        endif()
        if(_lib)
            list(REMOVE_ITEM _libs_out "${_lib}")
            list(APPEND _libs_out "${_lib}")
        endif()
    endwhile()
    string(REPLACE ";" " " _libs_out "${_libs_out}")
    set(${_result} "${_libs_out}" PARENT_SCOPE)
endfunction()

# Generate gdal-config utility command and pkg-config module gdal.pc
function(gdal_generate_config)
    set(one_value_keywords "TARGET;GLOBAL_PROPERTY;GDAL_CONFIG;PKG_CONFIG")
    cmake_parse_arguments(PARSE_ARGV 0 arg "" "${one_value_keywords}" "")

    if (ENABLE_GNM)
        set(CONFIG_GNM_ENABLED "yes")
    else ()
        set(CONFIG_GNM_ENABLED "no")
    endif ()
    get_property(gdal_formats GLOBAL PROPERTY GDAL_FORMATS)
    get_property(ogr_formats GLOBAL PROPERTY OGR_FORMATS)
    string(REPLACE ";" " " CONFIG_FORMATS "${gdal_formats} ${ogr_formats}")

    if(NOT DEFINED CMAKE_INSTALL_PREFIX)
        set(CONFIG_PREFIX "/usr/local") # default
    else()
        set(CONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}")
    endif()
    set(CONFIG_DATA "${CONFIG_PREFIX}/${GDAL_RESOURCE_PATH}")
    set(CONFIG_CFLAGS "-I${CONFIG_PREFIX}/${GDAL_INSTALL_INCLUDEDIR}")

    get_property(target_lib_name TARGET "${arg_TARGET}" PROPERTY OUTPUT_NAME)
    set(CONFIG_LIBS "${CMAKE_LINK_LIBRARY_FLAG}${target_lib_name}")
    if(NOT CONFIG_PREFIX IN_LIST CMAKE_C_IMPLICIT_LINK_LIBRARIES)
        string(PREPEND CONFIG_LIBS "${CMAKE_LIBRARY_PATH_FLAG}${CONFIG_PREFIX}/${CMAKE_INSTALL_LIBDIR} ")
    endif()

    get_property(libs GLOBAL PROPERTY "${arg_GLOBAL_PROPERTY}")
    if(NOT MSVC AND CMAKE_THREAD_LIBS_INIT)
        list(APPEND libs ${CMAKE_THREAD_LIBS_INIT})
    endif()
    list(APPEND libs ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
    if(CMAKE_C_IMPLICIT_LINK_LIBRARIES)
        list(REMOVE_ITEM libs ${CMAKE_C_IMPLICIT_LINK_LIBRARIES})
    endif()
    gdal_get_lflags(CONFIG_DEP_LIBS ${libs})
    if(NOT BUILD_SHARED_LIBS)
        # Make `--libs` simply work, even for static builds.
        string(APPEND CONFIG_LIBS " ${CONFIG_DEP_LIBS}")
        set(CONFIG_DEP_LIBS "")
    endif()

    configure_file("${GDAL_CMAKE_TEMPLATE_PATH}/gdal-config.in" "${arg_GDAL_CONFIG}" @ONLY)
    configure_file("${GDAL_CMAKE_TEMPLATE_PATH}/gdal.pc.in" "${arg_PKG_CONFIG}" @ONLY)
endfunction()
